import { NavBar, InfiniteScroll, Toast, Popup } from 'antd-mobile'
import { useHistory, useParams } from 'react-router-dom'
import classNames from 'classnames'
import styles from './index.module.scss'

import { Icon } from '@/components/Icon'
import CommentItem from './components/CommentItem'
import CommentFooter from './components/CommentFooter'

import { useInitialState } from '@/utils/use-initial-state'
import {
	getArticleById,
	followAuthor,
	collectArticle,
	likeArticle,
	articleCommentThumbUp,
	getArticleCommentsFirst,
	getArticleComments,
	addArticleComment,
	updateCommentCount,
} from '@/store/actions/article'

// 1、导入对 HTML 格式字符串消毒的包
import DOMPurify from 'dompurify'
// 导入代码高亮的包
import highlight from 'highlight.js'
// 导入代码高亮的样式
// 可以从 node_modules 中找到 highlight.js 包中提供的 CSS 样式
import 'highlight.js/styles/github-dark.css'
import { useEffect, useRef, useState } from 'react'

// loading 骨架屏组件 loading效果
import ContentLoader from 'react-content-loader'
// 4、导入 lodash 的节流函数
import throttle from 'lodash/throttle'
import { useDispatch } from 'react-redux'
import NoneComment from '@/components/NoneComment'
import CommentInput from './components/CommentInput'
import Reply from './components/Reply'
import { ArtComment } from '@/types/data'

/**
 * 导航栏高度的常量
 */
const NAV_BAR_HEIGTH = 45

// 创建枚举，来表示评论类型。 a 和 c 都是接口指定的
//CommentType.Article 表示文章的评论
// CommentType.Comment 表示评论的回复
enum CommentType {
	Article = 'a',
	Comment = 'c',
}

// 评论回复的弹出层需要的数据类型
type CommentReply = {
	/**
	 * 弹出层的展示或隐藏
	 */
	visible: boolean
	/**
	 * 评论项内容
	 */
	commentItem: ArtComment
}

const Article = () => {
	const dispatch = useDispatch()
	const history = useHistory()
	// // 获取路由参数
	const params = useParams<{ id: string }>()
	// // 表示文章是否加载中的状态
	const [loading, setLoading] = useState(true)
	// 1、创建文章可滚动区域的ref对象
	const wrapperRef = useRef<HTMLDivElement>(null)
	// 2、创建导航栏作者信息的ref对象
	const authorRef = useRef<HTMLDivElement>(null)
	// 3、创建控制导航栏中作者信息的展示和隐藏
	const [showNavAuthor, setShowNavAuthor] = useState(false)
	// 创建评论信息的DOM对象的 ref
	const commentRef = useRef<HTMLDivElement>(null)
	// 创建用来表示当前是否展示评论信息的ref
	const isShowComment = useRef(false)

	//  创建控制文章评论弹出层展示或隐藏的状态
	const [commentVisible, setCommentVisible] = useState(false)

	const onCommentShow = () => setCommentVisible(true)
	const onCommentHide = () => setCommentVisible(false)

	// 控制文章评论回复弹出层的展示或隐藏的状态
	const [showReply, setShowReply] = useState<CommentReply>({
		visible: false,
		commentItem: {} as ArtComment,
	})

	// 隐藏回复弹出层
	const onReplyHide = (commentId: string, total: number) => {
		// 修改redux中的评论列表数据
		dispatch(updateCommentCount(commentId, total))

		setShowReply({
			...showReply,
			visible: false,
		})
	}

	// 拿到准备好的 comment 数据
	//获取文章详情
	const { detail, comments } = useInitialState(
		() => getArticleById(params.id),
		'article',
		() => setLoading(false)
	)

	// 处理代码高亮
	useEffect(() => {
		const dgHtmlDOM = document.querySelector('.dg-html')
		const codes = dgHtmlDOM?.querySelectorAll<HTMLElement>('pre code')
		// console.log(codes)
		if (codes && codes.length > 0) {
			codes.forEach((el) => {
				// 让每个 code 内容实现代码高亮
				highlight.highlightElement(el)
			})
			return
		}

		highlight.configure({
			// 忽略警告
			ignoreUnescapedHTML: true,
		})

		// 直接找到所有的 pre 标签
		const pres = dgHtmlDOM?.querySelectorAll('pre')
		if (pres && pres.length > 0) {
			pres.forEach((el) => {
				highlight.highlightElement(el)
			})
		}
	}, [detail])

	// 给文章详情可滚动区域绑定滚动事件
	// 导航栏中展示作者信息
	useEffect(() => {
		if (loading) return
		const wrapperDOM = wrapperRef.current!
		// 创建一个节流函数 通过节流函数 throttle 来降低滚动事件的触发频率
		const handleScroll = throttle(() => {
			// height 表示：自己的高度
			// top 表示：距离页面顶部的距离
			const { bottom } = authorRef.current!.getBoundingClientRect()
			// 44 是 NavBar 的高度，因为 NavBar 会挡住页面内容，所以，此处需要减去它的高度
			if (bottom - 44 <= 0) {
				setShowNavAuthor(true)
			} else {
				setShowNavAuthor(false)
			}
		}, 200)

		wrapperDOM.addEventListener('scroll', handleScroll)
		return () => wrapperDOM.removeEventListener('scroll', handleScroll)
	}, [loading])

	// 点击跳转到评论内容
	// 展示 or 隐藏评论内容
	const onShowComment = () => {
		const wrapper = wrapperRef.current
		if (!wrapper) return
		const comment = commentRef.current
		if (!comment) return

		const commentTop = comment.getBoundingClientRect().top
		// console.log(commentTop)
		if (!isShowComment.current) {
			// 还没有展示评论信息，此时，就展示评论信息
			wrapper.scrollTo({
				// wrapper.scrollTop 表示已经滚动的距离
				top: commentTop - NAV_BAR_HEIGTH + wrapper.scrollTop,
				// 如果想要滚动时，带有动画效果，可以使用 smooth 即可
				behavior: 'auto',
			})
			isShowComment.current = true
		} else {
			// 已经展示评论信息，此时，需要返回页面顶部
			wrapper.scrollTo(0, 0)
			isShowComment.current = false
		}
	}

	// 对于文章的评论数据来说，第一次获取需要自己手动发送请求
	// 注意：为了避免脚手架热更新时，请求再次发送获取第一页数据重复，
	//所以，该请求我们使用覆盖数据，而不是追加数据
	useEffect(() => {
		//   // 注意：此处，我们通过 路由参数 params 来获取到文章 id
		// dispatch(getArticleComment(CommentType.Article, params.art_id, null))
		dispatch(getArticleCommentsFirst(CommentType.Article, params.id, null))
	}, [dispatch, params.id])

	//文章评论
	const { end_id, last_id } = comments
	// console.log(end_id, last_id)
	//是否有更多评论
	const hasMore = end_id !== last_id

	//以后每次 :InfiniteScroll 加载评论数据
	const loadMoreComments = async () => {
		// console.log('加载更多评论')
		await dispatch(
			getArticleComments(CommentType.Article, params.id, comments.last_id)
		)
	}

	// 关注 或 取消关注作者
	const onFollowAuthor = async () => {
		await dispatch(followAuthor(aut_id, is_followed))
		Toast.show({
			content: is_followed ? '已取消关注' : '已关注',
			duration: 800,
		})
	}

	// 收藏或取消收藏文章
	const onCollected = async () => {
		await dispatch(collectArticle(art_id, is_collected))
		Toast.show({
			content: is_followed ? '已取消收藏' : '已收藏',
			duration: 800,
		})
	}

	// 点赞文章或取消点赞
	const onLike = async () => {
		await dispatch(likeArticle(art_id, attitude))
		Toast.show({
			content: is_followed ? '已取消点赞' : '已点赞',
			duration: 800,
		})
	}

	// 发表评论
	const onAddComment = async (value: string) => {
		await dispatch(addArticleComment(art_id, value))

		//关闭评论弹框
		onCommentHide()
	}

	// 对评论点赞
	const onThumbUp = (com_id: string, is_liking: boolean) => {
		dispatch(articleCommentThumbUp(com_id, is_liking))
	}

	// 解构出文章详情数据：
	const {
		// target,
		art_id,
		aut_id,
		// // 是否点赞
		attitude,
		// // 是否收藏
		is_collected,
		is_followed,
		content,
		title,
		pubdate,
		aut_name,
		aut_photo,
		comm_count,
		like_count,
		read_count,
	} = detail

	// 2、如果是加载中，就展示 骨架屏loading 效果
	if (loading) {
		return (
			// 根据当前页面结构，设计好的 loading 效果
			<ContentLoader
				speed={2}
				width={375}
				height={230}
				viewBox='0 0 375 230'
				backgroundColor='#f3f3f3'
				foregroundColor='#ecebeb'
			>
				<rect x='16' y='8' rx='3' ry='3' width='340' height='10' />
				<rect x='16' y='26' rx='0' ry='0' width='70' height='6' />
				<rect x='96' y='26' rx='0' ry='0' width='50' height='6' />
				<rect x='156' y='26' rx='0' ry='0' width='50' height='6' />
				<circle cx='33' cy='69' r='17' />
				<rect x='60' y='65' rx='0' ry='0' width='45' height='6' />
				<rect x='304' y='65' rx='0' ry='0' width='52' height='6' />
				<rect x='16' y='114' rx='0' ry='0' width='340' height='15' />
				<rect x='263' y='208' rx='0' ry='0' width='94' height='19' />
				<rect x='16' y='141' rx='0' ry='0' width='340' height='15' />
				<rect x='16' y='166' rx='0' ry='0' width='340' height='15' />
			</ContentLoader>
		)
	}

	// 渲染文章详情
	const renderArticle = () => {
		return (
			<div className='wrapper' ref={wrapperRef}>
				{/* 文章详情 */}
				<div className='article-wrapper'>
					<div className='header'>
						<h1 className='title'>{title}</h1>

						<div className='info'>
							<span>{pubdate}</span>
							<span>{read_count} 阅读</span>
							<span>{comm_count} 评论</span>
						</div>

						<div className='author' ref={authorRef}>
							<img
								src={
									aut_photo ||
									'http://geek.itheima.net/images/user_head.jpg'
								}
								alt=''
							/>
							<span className='name'>{aut_name}</span>
						</div>

						<span
							onClick={onFollowAuthor}
							className={classNames(
								'follow',
								is_followed ? 'followed' : ''
							)}
						>
							{is_followed ? '已关注' : '关注'}
						</span>
					</div>
				</div>

				<div className='content'>
					{/* 文章详情 */}
					<div
						className='content-html dg-html'
						// HTML5 中规定：不执行 innerHTML 中的 script 标签
						// dangerouslySetInnerHTML={{ __html: '<script>alert(1)</script>' }}

						// 注意：此处图片的 onerror 属性的代码，还是会被执行，不仅影响了用户体验，还会存在 XSS 攻击问题
						// dangerouslySetInnerHTML={{
						//   __html: "<img src='x' onerror='alert(1)' />"
						// }}

						// 使用 DOMPurify 对 HTML 格式字符串内容进行消毒
						// dangerouslySetInnerHTML={{
						//   __html: DOMPurify.sanitize("<img src='x' onerror='alert(1)' />")
						// }}

						dangerouslySetInnerHTML={{
							__html: DOMPurify.sanitize(content),
						}}
					></div>
					<div className='date'>发布文章时间：{pubdate}</div>
				</div>

				{/* 文章评论 */}
				<div className='comment' ref={commentRef}>
					<div className='comment-header'>
						<span>全部评论（{comm_count}）</span>
						<span>{like_count} 点赞</span>
					</div>

					{/* 评论列表 */}
					{comments.results.length === 0 ? (
						<NoneComment />
					) : (
						<div className='comment-list'>
							{comments.results.map((item) => (
								<CommentItem
									{...item}
									key={item.com_id}
									onThumbUp={() =>
										onThumbUp(item.com_id, item.is_liking)
									}
									onReplyShow={() =>
										setShowReply({
											visible: true,
											commentItem: item,
										})
									}
								/>
							))}

							<InfiniteScroll
								hasMore={hasMore}
								loadMore={loadMoreComments}
							/>
						</div>
					)}
				</div>
			</div>
		)
	}

	// 渲染文章的评论弹出层
	const renderArticleComment = () => {
		return (
			<Popup
				bodyStyle={{
					height: '100%',
				}}
				position='bottom'
				visible={commentVisible}
				onMaskClick={onCommentHide}
			>
				<CommentInput
					onClose={onCommentHide}
					onAddComment={onAddComment}
				/>
			</Popup>
		)
	}

	// 渲染评论回复的弹出层
	const renderReply = () => {
		return (
			<Popup
				bodyStyle={{
					width: '100%',
				}}
				position='right'
				visible={showReply.visible}
				destroyOnClose
			>
				{/* <div className='comment-popup-wrapper'>
					<Reply CommentItem={} onClose={onReplyHide} />
				</div> */}
				<Reply
					onClose={onReplyHide}
					commentItem={showReply.commentItem}
					onReplyThumbUp={onThumbUp}
					articleId={params.id}
				/>
			</Popup>
		)
	}

	return (
		<div className={styles.root}>
			<div className='root-wrapper'>
				<NavBar
					onBack={() => history.go(-1)}
					right={
						<span>
							<Icon type='icongengduo' />
						</span>
					}
				>
					{showNavAuthor && (
						<div className='nav-author'>
							<img
								src={
									aut_photo ||
									'http://geek.itheima.net/images/user_head.jpg'
								}
								alt=''
							/>
							<span className='name'>{aut_name}</span>
							<span
								onClick={onFollowAuthor}
								className={classNames(
									'follow',
									is_followed ? 'followed' : ''
								)}
							>
								{is_followed ? '已关注' : '关注'}
							</span>
						</div>
					)}
				</NavBar>
				{/* 文章详情和评论 */}
				{renderArticle()}

				{/* 底部评论栏 */}
				<CommentFooter
					placeholder={comm_count === 0 ? '抢沙发' : '去评论'}
					comm_count={comm_count}
					is_collected={is_collected}
					attitude={attitude}
					onCollected={onCollected}
					onShowComment={onShowComment}
					onLike={onLike}
					onShowArticleComment={() => onCommentShow()}
				/>
			</div>

			{/* 创建文章评论的弹出层 */}
			{renderArticleComment()}

			{/* 文章评论回复的弹出层 */}
			{renderReply()}
		</div>
	)
}

export default Article
